﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NHibernate;
using NHibernate.Criterion;

namespace SmartProject.Entity
{
    /// <summary>
    /// The Task class allows the user to create jobs to work on.
    /// </summary>
    public class Task : EntityBase
    {
        /// <summary>
        /// Creates a new instance of Task.
        /// </summary>
        public Task()
        {
            Attachments = new List<Attachment>();
            Notes = new List<Note>();
        }

        /// <summary>
        /// Gets or sets the owner of this task.
        /// </summary>
        public virtual User Owner { get; set; }

        /// <summary>
        /// Gets or sets the user assigned to this task.
        /// </summary>
        public virtual User Assignee { get; set; }

        /// <summary>
        /// Gets or sets the product associated with this task.
        /// </summary>
        public virtual Product Product { get; set; }

        public virtual TaskCategory Category { get; set; }

        public virtual Sprint Sprint { get; set; }

        public virtual int? EstimatedTime { get; set; }

        public virtual int? ActualTime { get; set; }

        public virtual TimeType EstimatedTimeType { get; set; }

        public virtual TimeType ActualTimeType { get; set; }

        public virtual Priority Priority { get; set; }

        public virtual TaskStatus Status { get; set; }

        public virtual string Description { get; set; }

        public virtual DateTime? Started { get; set; }

        public virtual DateTime? DueDate { get; set; }

        public virtual DateTime? Assigned { get; set; }

        public virtual DateTime? Completed { get; set; }

        public virtual IList<Attachment> Attachments { get; private set; }

        public virtual IList<Note> Notes { get; set; }

        /// <summary>
        /// Gets task by task Id.
        /// </summary>
        /// <param name="session">Session used in this request.</param>
        /// <param name="taskId">Task Id.</param>
        /// <returns>Task instance.</returns>
        public static Task GetTask(ISession session, int taskId)
        {
            return (Task)EntityBase.GetEntity(session, taskId, typeof(Task));
        }

        /// <summary>
        /// Gets a list of tasks related to a Sprint Id.
        /// </summary>
        /// <param name="session">Session used in this request.</param>
        /// <param name="sprintId">Sprint Id.</param>
        /// <returns>List of tasks.</returns>
        public static IList<Task> GetTasks(ISession session, int sprintId)
        {
            IList<ICriterion> expressions = new List<ICriterion>();
            expressions.Add(Restrictions.Eq("SprintId", sprintId));
            return (from p in Find(session, null, null, typeof(Task)) select p as Task).ToList();
        }

        // No need?
        /*
        public static IList<Task> GetTasks(ISession session, string searchText, string fieldToOrder, bool ascending)
        {
            IList<ICriterion> expressions = new List<ICriterion>();
            expressions.Add(Expression.Or(Expression.Like("Description", String.Format("%{0}%", searchText)),
                Expression.Like("Description", String.Format("{0}%", searchText))));

            IList<Order> orderings = new List<Order>();
            if (ascending)
            {
                orderings.Add(Order.Asc(fieldToOrder));
            }
            else
            {
                orderings.Add(Order.Desc(fieldToOrder));
            }

            IList<EntityBase> entities = Find(session, expressions, orderings, typeof(Task));
            IList<Task> tasks = new List<Task>();
            for (int i = 0; i < entities.Count; i++)
            {
                tasks.Add((Task)entities[i]);
            }
            return tasks;
        }
        */
        public static IList<Task> GetAssigneeTasks(ISession session, string assignee, string fieldToOrder, bool ascending)
        {
            IList<ICriterion> expressions = new List<ICriterion>();
            expressions.Add(Restrictions.Eq("Assignee", User.GetUserByUsername(session, assignee)));
            IList<Order> orderings = new List<Order>();
            if (ascending)
            {
                orderings.Add(Order.Asc(fieldToOrder));
            }
            else
            {
                orderings.Add(Order.Desc(fieldToOrder));
            }
            IList<EntityBase> entities = Find(session, expressions, orderings, typeof(Task));
            IList<Task> tasks = new List<Task>();
            for (int i = 0; i < entities.Count; i++)
            {
                tasks.Add((Task)entities[i]);
            }
            return tasks;
        }

        public static IList<Task> GetOwnerTasks(ISession session, string owner, string fieldToOrder, bool ascending)
        {
            IList<ICriterion> expressions = new List<ICriterion>();
            expressions.Add(Restrictions.Eq("Owner", User.GetUserByUsername(session, owner)));
            IList<Order> orderings = new List<Order>();
            if (ascending)
            {
                orderings.Add(Order.Asc(fieldToOrder));
            }
            else
            {
                orderings.Add(Order.Desc(fieldToOrder));
            }
            IList<EntityBase> entities = Find(session, expressions, orderings, typeof(Task));
            IList<Task> tasks = new List<Task>();
            for (int i = 0; i < entities.Count; i++)
            {
                tasks.Add((Task)entities[i]);
            }
            return tasks;
        }

        /// <summary>
        /// Creates a new task with the most basic requirements.
        /// </summary>
        /// <param name="session">Session used in this request.</param>
        /// <param name="owner">Owner of the task.</param>
        /// <param name="productId">Product of this task.</param>
        /// <param name="priorityId"></param>
        /// <param name="description"></param>
        /// <returns></returns>
        public static Task NewTask(ISession session, string owner, int productId, int priorityId, int taskCategoryId, string description)
        {
            Task task = new Task();
            task.Owner = User.GetUserByUsername(session, owner);
            task.Product = Product.GetProduct(session, productId);
            task.Priority = Priority.GetPriority(session, priorityId);
            task.Status = TaskStatus.GetTaskStatus(session, "New");
            task.Description = description;
            task.Category = TaskCategory.GetTaskCategory(session, taskCategoryId);
            task.Save(session);
            return task;
        }

        public static Task NewTask(ISession session, int ownerId, int productId, int priorityId, int taskCategoryId, string description)
        {
            Task task = new Task();
            task.Owner = User.GetUser(session, ownerId);
            task.Product = Product.GetProduct(session, productId);
            task.Priority = Priority.GetPriority(session, priorityId);
            task.Status = TaskStatus.GetTaskStatus(session, "New");
            task.Description = description;
            task.Category = TaskCategory.GetTaskCategory(session, taskCategoryId);
            task.Save(session);
            return task;
        }

        /// <summary>
        /// Discard the current task and resets
        /// </summary>
        /// <param name="session">Session used in this request.</param>
        public virtual void Discard(ISession session)
        {
            Started = null;
            Assignee = null;
            Owner = null;
            Status = TaskStatus.GetTaskStatus(session, "New");
            Save(session);
        }

        /// <summary>
        /// Start the task.
        /// </summary>
        /// <param name="session">Session used in this request.</param>
        public virtual void Start(ISession session)
        {
            Started = DateTime.Now;
            Status = TaskStatus.GetTaskStatus(session, "In Progress");
            Save(session);
        }

        /// <summary>
        /// Hold the task.
        /// </summary>
        /// <param name="session">Session used in this request.</param>
        public virtual void Hold(ISession session)
        {
            Status = TaskStatus.GetTaskStatus(session, "On Hold");
            Save(session);
        }
    }
}
